#ifndef __KERN_MM_SWAP_H__
#define __KERN_MM_SWAP_H__

#include <defs.h>
#include <memlayout.h>
#include <pmm.h>
#include <vmm.h>

/* *
 * swap_entry_t
 * --------------------------------------------
 * |         offset        |   reserved   | 0 |
 * --------------------------------------------
 *           24 bits            7 bits    1 bit
 * */

#define MAX_SWAP_OFFSET_LIMIT (1 << 24)

extern size_t max_swap_offset;

/* *
 * swap_offset - takes a swap_entry (saved in pte), and returns
 * the corresponding offset in swap mem_map.
 * */
#define swap_offset(entry)                                   \
    ({                                                       \
        size_t __offset = (entry >> 8);                      \
        if (!(__offset > 0 && __offset < max_swap_offset)) { \
            panic("invalid swap_entry_t = %08x.\n", entry);  \
        }                                                    \
        __offset;                                            \
    })

struct swap_manager {
    const char *name;
    /* Global initialization for the swap manager */
    int (*init)(void);
    /* Initialize the priv data inside mm_struct */
    int (*init_mm)(struct mm_struct *mm);
    /* Called when tick interrupt occured */
    int (*tick_event)(struct mm_struct *mm);
    /* Called when map a swappable page into the mm_struct */
    int (*map_swappable)(struct mm_struct *mm, uintptr_t addr,
                         struct Page *page, int swap_in);
    /* When a page is marked as shared, this routine is called to
     * delete the addr entry from the swap manager */
    int (*set_unswappable)(struct mm_struct *mm, uintptr_t addr);
    /* Try to swap out a page, return then victim */
    int (*swap_out_victim)(struct mm_struct *mm, struct Page **ptr_page,
                           int in_tick);
    /* check the page relpacement algorithm */
    int (*check_swap)(void);
};

extern volatile int swap_init_ok;
int swap_init(void);
int swap_init_mm(struct mm_struct *mm);
int swap_tick_event(struct mm_struct *mm);
int swap_map_swappable(struct mm_struct *mm, uintptr_t addr, struct Page *page,
                       int swap_in);
int swap_set_unswappable(struct mm_struct *mm, uintptr_t addr);
int swap_out(struct mm_struct *mm, int n, int in_tick);
int swap_in(struct mm_struct *mm, uintptr_t addr, struct Page **ptr_result);

#endif
